import createElement from './create-element';
import mainExport from './main-export';
interface isComponent{
	(Component?: any): boolean;
}
interface renderComponent<Component, component>{
	(Component: Component, props: object, htmlElement: HTMLElement): component;
}
export type Exports<Component> = Component | { default?: Component | null } | null | undefined;
/**
 * 组件渲染管理器
 * @description render-vue-component 和 render-react-component 通过此类实现
 * @warn 请不要直接使用
 */
export default class ComponentRenderer<Component, component> {
	is: isComponent;
	_render: renderComponent<Component, component>;
	/**
	 * 
	 * @param isComponent 判断是否是组件的函数
	 * @param renderComponent 渲染组件的函数
	 */
	constructor(is: isComponent, render: renderComponent<Component, component>) {
		this.is = is;
		this._render = render;
	}
	/**
	 * 异步从一个模块的导出中获取组件
	 * @param Component 模块的导出，默认为入口模块
	 * @description 支持 ES Module 和 CJS 两种模块形式的导出
	 * @description 对于 ES Module ，为其默认导出
	 */
	async get(Component:Exports<Component> | Promise<Exports<Component>> = mainExport): Promise<Component | undefined> {
		Component = await Component;
		if (!Component) { return; }
		if (this.is(Component)) { return Component as Component; }
		Component = (Component as {default: Component | null}).default;
		if (this.is(Component)) { return Component as Component; }
	}
	/**
	 * 渲染组件到指定 HTMLElement 上
	 * @param Component 要渲染的组件
	 * @param htmlElement 要渲染出此组件的 HTMLElement
	 * @returns 返回创建的实例
	 */
	render(Component: Component, htmlElement: HTMLElement): component;
	/**
	 * 渲染组件
	 * @param Component 要渲染的组件
	 * @param props 渲染时的参数，如果留空则为 {}
	 * @param htmlElement 要渲染出此组件的 HTMLElement，如果留空则通过 create-element 模块自动创建
	 * @returns 返回创建的实例
	 */
	render(Component: Component, props?: object, htmlElement?: HTMLElement): component;
	render(Component: Component, props?: object | HTMLElement, htmlElement?: HTMLElement): component {
		if (props instanceof HTMLElement) { [props, htmlElement] = [undefined, props]; }
		if (!(htmlElement instanceof HTMLElement)) { htmlElement = createElement(); }
		return this._render(Component, props || {}, htmlElement);
	}
	/**
	 * 异步渲染默认导入的组件到指定 HTMLElement 上
	 * @param htmlElement 要渲染出此组件的 HTMLElement
	 * @returns 如果默认导出的为组件，将返回创建的实例
	 */
	async renderDefault(htmlElement: HTMLElement): Promise<component | undefined>;
	/**
	 * 异步渲染默认导入的组件
	 * @param props 渲染时的参数，如果留空则为 {}
	 * @param htmlElement 要渲染出此组件的 HTMLElement，如果留空则通过 create-element 模块自动创建
	 * @returns 如果默认导出的为组件，将返回创建的实例
	 */
	async renderDefault(props?: object, htmlElement?: HTMLElement): Promise<component | undefined>;
	async renderDefault(props?: object | HTMLElement, htmlElement?: HTMLElement): Promise<component | undefined> {
		if (props instanceof HTMLElement) { [props, htmlElement] = [undefined, props]; }
		if (!(htmlElement instanceof HTMLElement)) { htmlElement = createElement(); }
		const Component = await this.get();
		if (!Component) { return; }
		return this.render(Component, props, htmlElement);
	}
}
